package com.open.capacity.finance.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.open.capacity.finance.config.Globals;
import com.open.capacity.finance.dao.AuditAnalysisDao;
import com.open.capacity.finance.dao.SourceBaseCustomItemDao;
import com.open.capacity.finance.dao.SourceBaseCustomValueDao;
import com.open.capacity.finance.dao.SourceBaseKjkmExtDao;
import com.open.capacity.finance.dto.AuditModelBaseResult;
import com.open.capacity.finance.dto.SourceZcfzbErrorDto;
import com.open.capacity.finance.dto.audit_model_12.AuditModelResult;
import com.open.capacity.finance.dto.audit_model_12.AuditModelStep1;
import com.open.capacity.finance.dto.audit_model_12.AuditModelStep2;
import com.open.capacity.finance.dto.audit_model_12.ExcelData;
import com.open.capacity.finance.entity.AuditModel;
import com.open.capacity.finance.entity.AuditModelRule;
import com.open.capacity.finance.entity.SourceBaseCustomValue;
import com.open.capacity.finance.entity.SourceBaseKjkmExt;
import com.open.capacity.finance.service.AbstractAuditMakeResultFactory;
import com.open.capacity.finance.service.AuditModelRuleService;
import com.open.capacity.finance.service.AuditModelService;
import com.open.capacity.finance.util.FileUtil;
import com.open.capacity.reptile.entity.GdszczMaEleAcco;
import com.open.capacity.user.model.SysCompany;
import com.open.capacity.utils.DateUtil;
import com.open.capacity.utils.StringUtil;
import com.open.capacity.utils.encrypt.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AuditModelActuator12ServiceImpl<T extends AuditModelBaseResult> extends AbstractAuditMakeResultFactory {

    @Autowired
    private AuditAnalysisDao analysisDao;

    @Autowired
    private SourceBaseKjkmExtDao kjkmExtDao;
    @Autowired
    private SourceBaseCustomItemDao customItemDao;
    @Autowired
    private SourceBaseCustomValueDao customValueDao;

    @Autowired
    private AuditModelRuleService ruleService;
    @Autowired
    private AuditModelService modelService;

    //'项目','在建工程及预付账款项目'为在建工程项目。
    private static final String CUSTOMITEMCODE = "PROJECT,ACC_ITEM09";

    @Override
    protected T analyseResultData(String modelId, Map param) {
        String companyId = param.containsKey("companyId") ? param.get("companyId").toString() : "";
        param.put("ztId", "101");
        String xmName = param.containsKey("xmName") ? param.get("xmName").toString() : null;
        AuditModelResult result = new AuditModelResult();
        AuditModel model = modelService.findById(modelId);
        Assert.notNull(model, "找不到该模型");
        List<AuditModelRule> rules = ruleService.findByModelId(modelId);

        AtomicReference<String> xmField = new AtomicReference<>("1");
        AtomicInteger continueYear = new AtomicInteger(3);
        AtomicInteger startYear = new AtomicInteger(DateUtil.twoYearAgo());
        rules.forEach(t -> {
            if (t.getConfKey().equals("xmField")) {
                xmField.set(t.getConfValue());
            }
            if (t.getConfKey().equals("continueYear")) {
                continueYear.set(Integer.parseInt(t.getConfValue()));
                startYear.set(DateUtil.getYear() - Integer.parseInt(t.getConfValue()));
            }
            param.put(t.getConfKey(), t.getConfValue());
        });
        param.put("startYear", startYear.get());
        result.setModelName(model.getCodeAndName());

        List<AuditModelStep1> step1List = new ArrayList<>();
        List<AuditModelStep1> list = analysisDao.model12(param);

        //填充辅助项信息
        //fillExtData(param, list);

        if (CollectionUtils.isNotEmpty(list)) {
            HashMap<String, List<AuditModelStep1>> collect = list.stream().collect(Collectors.groupingBy(t -> t.getCompanyId() + "_" + "_" + t.getKjkmCode() + "_" + t.getXmCode(), HashMap::new, Collectors.toList()));
            for (Map.Entry<String, List<AuditModelStep1>> entry : collect.entrySet()) {
                if (entry.getValue().size() >= continueYear.get()) {
                    step1List.addAll(entry.getValue());
                }
            }
        }


        if (StringUtil.isNotEmpty(xmName)) {
            step1List = step1List.stream().filter(t -> t.getXmCodeAndName().contains(xmName)).collect(Collectors.toList());
        }

        List<AuditModelStep2> step2List = new ArrayList<>();
        Map<String, List<AuditModelStep1>> collect = step1List.stream().collect(Collectors.groupingBy(t -> t.getCompanyId() + "_" + "_" + t.getKjkmCode() + "_" + t.getXmCode(), HashMap::new, Collectors.toList()));
        for (Map.Entry<String, List<AuditModelStep1>> entry : collect.entrySet()) {
            String key = entry.getKey();
            String _companyId = key.split("_")[0];
            String kjkmCode = key.split("_")[1];
            String xmCode = key.split("_")[2];

            if (entry.getValue().size() == continueYear.get()) {
                AuditModelStep2 item = new AuditModelStep2();
                item.setCompanyId(_companyId);
                item.setKjkmCode(kjkmCode);

                Optional<SysCompany> company = Globals.companyList.stream().filter(c -> c.getId().equals(item.getCompanyId())).findFirst();
                if(company.isPresent()){
                    item.setCompanyName(company.get().getFullName());
                }
                Optional<GdszczMaEleAcco> kjkm = Globals.kjkmList.stream().filter(c -> c.getAgencyCode().equals(item.getCompanyId()) && c.getSetYear().equals(item.getKjnd()) && c.getChrCode().equals(item.getKjkmCode())).findFirst();
                if (kjkm.isPresent()) {
                    item.setKjkmName(kjkm.get().getChrName());
                }
                item.setXmCode(xmCode);
                item.setXmName(entry.getValue().get(0).getXmName());
                BigDecimal lastQm = entry.getValue().stream().filter(t -> t.getKjnd().equals(DateUtil.getYear())).findFirst().get().getQm();
                BigDecimal preQm = entry.getValue().stream().filter(t -> t.getKjnd().equals(startYear.get() - 1)).findFirst().get().getQm();
                item.setScale((lastQm.multiply(preQm)).divide(preQm,BigDecimal.ROUND_HALF_UP).doubleValue());
                step2List.add(item);
            }
        }

        if (CollectionUtils.isEmpty(step2List)) {
            result.setExists(0);
        } else {
            result.setExists(1);

            //持久化本地
            persistence(result);
        }

        result.setCompanyId(companyId);
        step1List.forEach(t -> {
            Optional<SysCompany> first = Globals.companyList.stream().filter(c -> c.getId().equals(t.getCompanyId())).findFirst();
            if (first.isPresent()) {
                t.setCompanyName(first.get().getFullName());
            }
        });

        step1List.sort(Comparator.comparing(AuditModelStep1::getCompanyId)
                .thenComparing(AuditModelStep1::getKjnd)
                .thenComparing(AuditModelStep1::getKjkmCode)
                .thenComparing(AuditModelStep1::getXmCode));
        
        result.setStep1List(step1List);
        result.setStep2List(step2List);

        return (T) result;
    }

    @Override
    protected int persistence(AuditModelBaseResult data) {
        int result = 0;

        String content = JSON.toJSONString(data, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);

        data.setResultFileMd5(Md5Utils.hash(content));
        data.setResultFileUrl("/upload/analyse/model12_" + data.getCompanyId() + "_" + data.getResultFileMd5() + ".json");

        Writer write = null;
        try {
            File file = new File(fileuploadPath + "/upload/analyse/model12_" + data.getCompanyId() + "_" + data.getResultFileMd5() + ".json");
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            // 写入文件
            write = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
            write.write(content);
            write.flush();
            write.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                write.close();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
        return result;
    }

    @Override
    public T getData(String modelId, Map param) {
        return analyseResultData(modelId, param);
    }

    /**
     * 填充辅助项信息
     */
    private void fillExtData(Map param, List<AuditModelStep1> step1List) {
        List<SourceBaseCustomValue> customValueList = customValueDao.findAll(param);
        List<SourceBaseKjkmExt> kjkmExtAllList = kjkmExtDao.findAll(param);

        Map<String, List<AuditModelStep1>> collect = step1List.stream().collect(Collectors.groupingBy(t -> t.getCompanyId() + "_" + t.getKjnd() + "_" + t.getKjkmCode(), HashMap::new, Collectors.toList()));

        List<SourceBaseKjkmExt> kjkmExts;
        for (Map.Entry<String, List<AuditModelStep1>> entry : collect.entrySet()) {
            String key = entry.getKey();
            String companyId = key.split("_")[0];
            Integer kjnd = Integer.parseInt(key.split("_")[1]);
            String kjkmCode = key.split("_")[2];

            kjkmExts = kjkmExtAllList.stream().filter(t -> t.getCompanyId().equals(companyId) && t.getKjnd().equals(kjnd) && t.getKjkmCode().equals(kjkmCode)).collect(Collectors.toList());
            kjkmExts.forEach(t -> {
                for (AuditModelStep1 auditModelStep1 : entry.getValue()) {
                    Optional<SourceBaseCustomValue> first = null;
                    switch (t.getExtCode()) {
                        case "1":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt1())).findFirst();
                            break;
                        case "2":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt2())).findFirst();
                            break;
                        case "3":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt3())).findFirst();
                            break;
                        case "4":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt4())).findFirst();
                            break;
                        case "5":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt5())).findFirst();
                            break;
                        case "6":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt6())).findFirst();
                            break;
                        case "7":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt7())).findFirst();
                            break;
                        case "8":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt8())).findFirst();
                            break;
                        case "9":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt9())).findFirst();
                            break;
                        case "10":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt10())).findFirst();
                            break;
                        case "11":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt11())).findFirst();
                            break;
                        case "12":
                            first = customValueList.stream().filter(c -> c.getCompanyId().equals(companyId) && c.getKjnd().equals(kjnd) && CUSTOMITEMCODE.contains(c.getItemCode()) && c.getCode().equals(auditModelStep1.getExt12())).findFirst();
                            break;
                    }
                    if (first != null && first.isPresent()) {
                        auditModelStep1.setXmCode(first.get().getCode());
                        auditModelStep1.setXmName(first.get().getName());
//                        auditModelStep1.setXmCodeAndName(first.get().getCode() + " " + first.get().getName());
                    }
                }
            });

        }

    }


    /**
     * 从本地加载数据
     */
    public AuditModelBaseResult getDataFromJson(String jsonUrl, Map param) {
        AuditModelResult result = null;
        try {
            String json = FileUtil.readTxtToJson(fileuploadPath + jsonUrl);
            result = JSONObject.parseObject(json, new TypeReference<AuditModelResult>() {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        filterCondition(result, param);

        return result;
    }

    /**
     * 本地json数据条件过滤
     */
    private AuditModelResult filterCondition(AuditModelResult orig, Map param) {
        AuditModelResult result = orig;
        String companyId = MapUtils.getString(param, "companyId");
        Integer kjnd = MapUtils.getInteger(param, "kjnd");
        String xmName = MapUtils.getString(param, "xmName");

        List<AuditModelStep1> list1 = orig.getStep1List();
        List<AuditModelStep2> list2 = orig.getStep2List();

        if (StringUtil.isNotEmpty(companyId)) {
            list1 = list1.stream().filter(t -> t.getCompanyId().equals(companyId)).collect(Collectors.toList());
            list2 = list2.stream().filter(t -> t.getCompanyId().equals(companyId)).collect(Collectors.toList());
        }
        if (kjnd != null) {
            list1 = list1.stream().filter(t -> t.getKjnd().equals(kjnd)).collect(Collectors.toList());
            list2 = list2.stream().filter(t -> t.getKjnd().equals(kjnd)).collect(Collectors.toList());
        }
        if (StringUtil.isNotEmpty(xmName)) {
            list1 = list1.stream().filter(t -> t.getXmName().contains(xmName)).collect(Collectors.toList());
            list2 = list2.stream().filter(t -> t.getXmName().contains(xmName)).collect(Collectors.toList());
        }

        result.setStep1List(list1);
        result.setStep2List(list2);

        return result;
    }

    public void exportExcel(String modelId, Map params, HttpServletResponse response) {
        AuditModelResult t = (AuditModelResult) analyseResultData(modelId, params);

        export(t, response);
    }

    @Override
    public void exportExcelFromJson(String modelId, String jsonUrl, HttpServletResponse response) {
        AuditModelResult t = null;
        try {
            String json = FileUtil.readTxtToJson(fileuploadPath + jsonUrl);
            t = JSONObject.parseObject(json, new TypeReference<AuditModelResult>() {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

        export(t, response);
    }

    private void export(AuditModelResult t, HttpServletResponse response) {
        List<ExcelData> result = t.getStep1List().stream().map(item -> {
            ExcelData model = new ExcelData();
            BeanUtils.copyProperties(item, model);
            return model;
        }).collect(Collectors.toList());

        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename=download_12.xls");
        OutputStream ouputStream = null;
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(),
                ExcelData.class, result);
        try {
            ouputStream = response.getOutputStream();
            workbook.write(ouputStream);
        } catch (Exception e) {
            throw new RuntimeException("系统异常");
        } finally {
            try {
                if (ouputStream != null) {
                    ouputStream.flush();
                    ouputStream.close();
                }
            } catch (Exception e) {
                throw new RuntimeException("系统异常");
            }
        }
    }
}
